﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Xml.Linq;
using HPPNet;
using HPPUtil;
using HPPUtil.Extensions;
using BitArray=HPPUtil.BitArray;

namespace HPPClientLibrary
{
    public class CSServer : HTTPServer
    {
        /// <summary>
        /// 每一块的大小，为固定值
        /// </summary>
        private readonly int BLOCKSIZE = BasicSetting.BlockSize;  // change const to readonly for unitTest & fitting to logic ,by vls, 2009-08-24

        /// <summary>
        /// 解释url后得到的信息
        /// </summary>


        private IClient _client; 

        public CSServer(IClient client, int numConnections, int receiveBufferSize) : base(numConnections, receiveBufferSize)
        {
            CommonLogger.Logger.Debug("CSServer Constructor");
            _client = client;
        }
        /// <summary>
        /// 解释请求的url
        /// </summary>
        /// <param name="urlInfo">存储文件名、文件的hash值及要请求的块号的一个hash表</param>
        /// <param name="url">请求的url</param>
        protected void ParseUrl(out Hashtable urlInfo, string url)
        {
            urlInfo = null;
            if (string.IsNullOrEmpty(url))
            {
                //urlInfo = null;
                return;
            }            
            Response response;
            
            string fileName = "",hash = "",blockNum = "";
            urlInfo = new Hashtable();
            if (url.IndexOf("|") < 0)
            {
                urlInfo = null;
                return;
            }
            else if (url.EndsWith("/") || url.LastIndexOf("/") == 0)
            {
                int pos = url.IndexOf("|");
              
                blockNum = "none";
                if (url.EndsWith("/") && url.IndexOf("/") == 0) //url格式为：  /abc.txt|hash/
                {
                    int lastPos = url.IndexOf("/", url.IndexOf("/") + 1);
                    fileName = url.Substring(1, pos - 1);
                    hash = url.Substring(pos + 1, lastPos - 1 - pos);                    
                }
                else if(url.IndexOf("/") == 0)// url格式为： /abc.txt|hash
                {
                    fileName = url.Substring(1, pos - 1);
                    hash = url.Substring(pos + 1, url.Length - 1 - pos);
                }
                else if(url.IndexOf("/") == url.Length - 1)//url 格式为: abc.txt|hash/
                {
                    fileName = url.Substring(0, pos);
                    hash = url.Substring(pos + 1, url.Length - pos - 2);
                }

            }
            else if (url.LastIndexOf("/") >= 0 && url.LastIndexOf("/") != url.Length - 1)// url格式为：  /abc.txt|hash/22
            {
                int pos = url.IndexOf("|");
                int lastPos = url.IndexOf("/", url.IndexOf("/") + 1);
                fileName = url.Substring(1, pos - 1);
                hash = url.Substring(pos + 1, lastPos - 1 - pos);
                blockNum = url.Substring(lastPos + 1, url.Length - lastPos - 1);

            }
            else if(url.IndexOf("/") < 0)//url 里没有包含 /,格式为: abc.txt|hash
            {
                int pos = url.IndexOf("|");
                fileName = url.Substring(0, pos);
                hash = url.Substring(pos + 1, url.Length - pos - 1);
            }
                urlInfo.Add("FileName",fileName);
                urlInfo.Add("Hash",hash);
                urlInfo.Add("BlockNum",blockNum);
        }

        protected override Response ProcessHttpReq(EndPoint remoteEndPoint, Hashtable headers, string body)
        {
            Response response = null;
            Hashtable urlInfo;

            if (remoteEndPoint == null || headers == null)
            {
                return response;
            }
            string url = String.Empty;
            if (headers.ContainsKey("Url"))
            {
                url = (string) headers["Url"];
            }
            ParseUrl(out urlInfo,url);
            if(urlInfo == null)
            {
                return response;
            }
            //TestParseUrl(url);
            //TestGetHasFilBlocks();
            //TestGetDownLoadFile();
            //return null;
            if (urlInfo.ContainsKey("BlockNum"))
            {
                if ((string)urlInfo["BlockNum"] == "none")
                {
                    if (urlInfo.ContainsKey("Hash"))
                    {
                        if (((string)urlInfo["Hash"]).Trim().ToString() == "")
                        {
                            response = null;
                        }
                        else
                        {
                            response = new StringResponse(GetOwnedFileBlocks((string)urlInfo["Hash"]));
                        }
                    }
                }
                else
                {
                    if (urlInfo.ContainsKey("Hash") && ((string)urlInfo["Hash"]).Trim().ToString() != "" && ((string)urlInfo["BlockNum"]).Trim().ToString() != "")
                    {
                        response = GetDownLoadFile((string) urlInfo["Hash"],Convert.ToInt32((string)urlInfo["BlockNum"]));
                    }
                }
            }
            return response;
        }
        /// <summary>
        /// 根据文件的hash值查找拥有该文件哪些块
        /// </summary>
        /// <param name="fileHash">文件的hash值</param>
        /// <returns>拥有该文件哪些块的xml格式的字符串</returns>
        protected string GetOwnedFileBlocks(string fileHash)
        {
            CommonLogger.Logger.Fatal("CSServer GetOwnedFileBlocks");
            if (fileHash == null)
            {
                return OwnedFileBlocksXO.Empty.ToCompleteString();
            }
            if (_client.ReadOnlyKnownDict.Contains(fileHash))
            {
                if(_client.ReadOnlyHashFileInfoDict.ContainsKey(fileHash))
                {
                    long blockCount;
                    if (_client.ReadOnlyHashFileInfoDict[fileHash].Len % BasicSetting.BlockSize == 0)
                    {
                        blockCount = _client.ReadOnlyHashFileInfoDict[fileHash].Len/BasicSetting.BlockSize;
                    }
                    else
                    {
                        blockCount = _client.ReadOnlyHashFileInfoDict[fileHash].Len/BasicSetting.BlockSize + 1;
                    }
                    BitArray bitArray = new BitArray((int)blockCount);
                    bitArray.SetAllPosTrue();
                    OwnedFileBlocksXO ownedFileBlocksXo = new OwnedFileBlocksXO(fileHash,bitArray.GetHexString());
                    return ownedFileBlocksXo.ToXml().ToCompleteString();
                }
            }

            if (_client.DownloadManager.HashJobInfoDict.ContainsKey(fileHash))
            {

                OwnedFileBlocksXO ownedFileBlocksXo = new OwnedFileBlocksXO(fileHash,  _client.DownloadManager.HashJobInfoDict[fileHash].LocalFileBlocks.GetHexString());

                return ownedFileBlocksXo.ToXml().ToCompleteString();
            }
            return OwnedFileBlocksXO.Empty.ToCompleteString();
        }

        /// <summary>
        /// 根据文件的hash值及要找的块的编号，得到一个FileResponse的对象
        /// </summary>
        /// <param name="fileHash">文件的hash值</param>
        /// <param name="blockNum">要找的哪一块</param>
        /// <returns></returns>
        protected FileResponse GetDownLoadFile(string fileHash,int blockNum)
        {
            if (string.IsNullOrEmpty(fileHash) || _client.DownloadManager == null || _client.DownloadManager.HashJobInfoDict == null)
            {
                return null;
            }
         
            if ((_client.DownloadManager.HashJobInfoDict.ContainsKey(fileHash) && _client.DownloadManager.HashJobInfoDict[fileHash].LocalFileBlocks.IsHasBlock(blockNum) == false) && _client.ReadOnlyHashFileInfoDict.ContainsKey(fileHash) == false) 
            {
                Console.WriteLine("没有找到所需的块！");
                CommonLogger.Logger.Fatal("CSServer 没有找到所需的块");
                return null;
            }


            int lastBlockSize;
            int blockAmount;
            long fileLen = 0;// _client.DownloadManager.HashJobInfoDict[fileHash].FileLen; 
            if (_client.ReadOnlyKnownDict.Contains(fileHash))
            {
                if (_client.ReadOnlyHashFileInfoDict.ContainsKey(fileHash))
                {
                    fileLen = _client.ReadOnlyHashFileInfoDict[fileHash].Len;
                }
            }
            else if (_client.DownloadManager.HashJobInfoDict.ContainsKey(fileHash) && _client.DownloadManager.HashJobInfoDict[fileHash].FileLen > 0)
            {
                fileLen = _client.DownloadManager.HashJobInfoDict[fileHash].FileLen;
            }
            //else
            //{
            //    fileLen = _client.ReadOnlyHashFileInfoDict[fileHash].Len;
            //}
                
            if (fileLen % BLOCKSIZE == 0)
            {
                blockAmount = (int)fileLen / BLOCKSIZE;
                lastBlockSize = BLOCKSIZE;
            }
            else
            {
                blockAmount = (int)fileLen / BLOCKSIZE + 1;
                lastBlockSize = (int)fileLen % BLOCKSIZE;
            }


            string fileName = _client.ReadOnlyHashFileInfoDict[fileHash].FullPathName;
            long beginPos;
            long endPos;
            if (blockNum != blockAmount)
            {
                beginPos = (blockNum - 1)*BLOCKSIZE;
                endPos = beginPos + BLOCKSIZE - 1;                
            }
            else
            {
                if (lastBlockSize == BLOCKSIZE)
                {
                     beginPos = (blockNum - 1)*BLOCKSIZE;
                     endPos = beginPos + BLOCKSIZE - 1;     
                }
                else
                {
                    beginPos = (blockNum - 1) * BLOCKSIZE;
                    endPos = beginPos + lastBlockSize - 1;
                }
            }

            FileResponse fileResponse = new FileResponse(fileName);
            fileResponse.HasRange = true;
            fileResponse.RangeBegin = beginPos;
            fileResponse.RangeEnd = endPos;
            return fileResponse;
        }
    }
}
